-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(math/curves): implement abstract Curve class and multiple different curve types. #4
Conversation
…ent curve types. This commit adds the following curve types: - ExponentialCurve - y = (x/|x|) * ((1 + exaggeration)^|x| - 1) / exaggeration. - LimitedCurve - Limits another curve to a minimum and maximum value. - LinearCurve - y = mx + b - PiecewiseCurve - Piecewise functions using Java lambdas/functions for conditions - QuadraticCurve - Ax^2 + Bx + C - RadicalCurve - y = (x+C)^(1/A)+B - TimedCurve - An abstract curve that toggles between two outputs based on a timer. - NormalTimedCurve - A TimedCurve that toggles between x (when enabled) and curve(x) (when disabled). - DoubleTimedCurve - A TimedCurve that toggles between two curves. - ZeroTimedCurve - A TimedCurve that toggles between 0 (when disabled) and curve(x) (when enabled).
…theses make the equation easier to read.
….setExaggeration(double)
… primitive for null safety
…structor of ExponentialCurve
…s added in previous commits
…ed and TimedCurve.setDelayEnabled
Warning Rate limit exceeded@Baconing has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 14 minutes and 18 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. WalkthroughThe pull request introduces several new classes related to mathematical curves in the robotics library, enhancing the functionality for curve manipulation. A new dependency on the WPIMath library is added to the Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Curve
participant TimedCurve
participant ZeroTimedCurve
User->>Curve: Create curve instance
Curve->>User: Return curve object
User->>TimedCurve: Create timed curve instance
TimedCurve->>User: Return timed curve object
User->>ZeroTimedCurve: Create zero timed curve instance
ZeroTimedCurve->>User: Return zero timed curve object
User->>TimedCurve: Enable curve
TimedCurve->>Curve: Evaluate curve
Curve->>TimedCurve: Return curve value
TimedCurve->>User: Return enabled curve value
User->>ZeroTimedCurve: Disable curve
ZeroTimedCurve->>User: Return zero
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 12
🧹 Outside diff range and nitpick comments (22)
src/main/java/net/frc5183/librobot/math/curve/Curve.java (2)
3-5
: Consider enhancing the class-level Javadoc.While the current Javadoc is clear and concise, it could be more informative. Consider adding details about:
- The expected usage of this abstract class.
- Any implementation requirements for subclasses.
- The significance of this class in the context of the robotics library.
This additional information would provide better guidance for developers working with or extending this class.
Here's a suggested enhancement:
/** * An abstract class which represents a mathematical function/curve. * <p> * This class serves as a base for various curve implementations in the robotics library. * Subclasses should implement the {@link #curve(Double)} method to define specific * mathematical behaviors. * <p> * Typical usage involves creating concrete subclasses for different types of curves * (e.g., linear, quadratic, exponential) and using them for calculations in robot control systems. */
7-11
: Consider enhancing the method-level Javadoc.The current Javadoc for the
curve
method is good, but it could be improved with some additional details:
- Mention any potential exceptions that might be thrown (if applicable).
- Provide information about how the method handles edge cases or special values (e.g., null, infinity, NaN).
- If there are any constraints on the input or output, they should be documented.
Here's a suggested enhancement:
/** * Returns the value of the curve at the given x value. * * @param x The x value to evaluate the curve at. * @return The value of the curve at the given x value. * @throws NullPointerException if x is null * @implSpec Implementations should handle special cases such as infinity and NaN appropriately. * The behavior for these cases should be clearly defined in the implementing class. */src/main/java/net/frc5183/librobot/math/curve/ExponentialCurve.java (3)
3-7
: Enhance the class-level Javadoc for clarity.The Javadoc comment provides a good overview of the class purpose and the mathematical formula. However, it could be improved for better clarity and understanding.
Consider updating the Javadoc as follows:
/** * An {@link Curve} implementation representing an exponential function. * <p> * The curve is defined by the equation: * y = (x/|x|) * ((1 + k)^|x| - 1) / k * <p> * Where: * <ul> * <li>x is the input value</li> * <li>k is the exaggeration parameter of the curve</li> * </ul> * This curve provides a customizable exponential response with the exaggeration parameter. */This enhancement provides a clearer structure and explains the variables in the equation.
13-19
: Minor enhancement to constructor Javadoc.The constructor's Javadoc is good, but we can improve it slightly for better documentation.
Consider updating the Javadoc as follows:
/** * Creates a new {@link ExponentialCurve} with the specified exaggeration. * * @param exaggeration The exaggeration parameter of the curve. Higher values result in a more pronounced curve. */This change provides more context about the exaggeration parameter's effect on the curve.
21-27
: Approve implementation with minor suggestion.The
curve
method correctly implements the exponential curve formula and handles the special case for x = 0. The use ofMath.abs()
andMath.pow()
is appropriate.Consider adding braces to the if statement for consistency and to follow best practices:
@Override public Double curve(Double x) { if (x == 0) { return 0d; } return (x / Math.abs(x)) * ((Math.pow(1 + exaggeration, Math.abs(x))) - 1) / exaggeration; }This change addresses the PMD warning about control statement braces and improves code consistency.
🧰 Tools
🪛 GitHub Check: pmd
[warning] 23-23: This statement should have braces
Enforce a policy for braces on control statements. It is recommended to use braces on 'if ... else'
statements and loop statements, even if they are optional. This usually makes the code clearer, and
helps prepare the future when you need to add another statement. That said, this rule lets you control
which statements are required to have braces via properties.From 6.2.0 on, this rule supersedes WhileLoopMustUseBraces, ForLoopMustUseBraces, IfStmtMustUseBraces,
and IfElseStmtMustUseBraces.ControlStatementBraces (Priority: 3, Ruleset: Code Style)
https://docs.pmd-code.org/pmd-doc-7.6.0/pmd_rules_java_codestyle.html#controlstatementbraces
[warning] 26-26: Useless parentheses.
Parenthesized expressions are used to override the default operator precedence
rules. Parentheses whose removal would not change the relative nesting of operators
are unnecessary, because they don't change the semantics of the enclosing expression.Some parentheses that strictly speaking are unnecessary, may still be considered useful
for readability. This rule allows to ignore violations on two kinds of unnecessary parentheses:
- "Clarifying" parentheses, which separate operators of difference precedence. While
unnecessary, they make precedence rules explicit, which may be useful for rarely used
operators. For example:(a + b) & c // is equivalent to `a + b & c`, but probably clearerUnset the property
ignoreClarifying
to report them.
- "Balancing" parentheses, which are unnecessary but visually balance out another pair
of parentheses around an equality operator. For example, those two expressions are equivalent:(a == null) != (b == null) a == null != (b == null)The parentheses on the right are required, and the parentheses on the left are
just more visually pleasing. Unset the propertyignoreBalancing
to report them.UselessParentheses (Priority: 4, Ruleset: Code Style)
https://docs.pmd-code.org/pmd-doc-7.6.0/pmd_rules_java_codestyle.html#uselessparentheses
[warning] 26-26: Useless parentheses.
Parenthesized expressions are used to override the default operator precedence
rules. Parentheses whose removal would not change the relative nesting of operators
are unnecessary, because they don't change the semantics of the enclosing expression.Some parentheses that strictly speaking are unnecessary, may still be considered useful
for readability. This rule allows to ignore violations on two kinds of unnecessary parentheses:
- "Clarifying" parentheses, which separate operators of difference precedence. While
unnecessary, they make precedence rules explicit, which may be useful for rarely used
operators. For example:(a + b) & c // is equivalent to `a + b & c`, but probably clearerUnset the property
ignoreClarifying
to report them.
- "Balancing" parentheses, which are unnecessary but visually balance out another pair
of parentheses around an equality operator. For example, those two expressions are equivalent:(a == null) != (b == null) a == null != (b == null)The parentheses on the right are required, and the parentheses on the left are
just more visually pleasing. Unset the propertyignoreBalancing
to report them.UselessParentheses (Priority: 4, Ruleset: Code Style)
https://docs.pmd-code.org/pmd-doc-7.6.0/pmd_rules_java_codestyle.html#uselessparenthesessrc/main/java/net/frc5183/librobot/math/curve/NormalTimedCurve.java (2)
1-6
: Enhance class documentation for clarity.The class documentation provides a concise description of the functionality. However, it could be improved by adding more details about the purpose and usage of the class.
Consider expanding the class documentation to include:
- A brief explanation of what a
TimedCurve
is.- The specific use case or scenario where
NormalTimedCurve
would be beneficial.- An example of how the class toggles between
x
andcurve(x)
.Here's a suggested improvement:
/** * A {@link TimedCurve} that toggles between x (when disabled) and curve(x) (when enabled). * This class is useful in scenarios where you need to apply a curve transformation * to an input value for a specific duration, then revert to the original input. * * For example, it can be used in robotics control systems to temporarily modify * input values based on certain conditions or time intervals. * * When enabled: output = curve(x) * When disabled: output = x */
23-31
: LGTM with a suggestion: Consider adding null check inenabled
method.The implementations of
enabled
anddisabled
methods are correct and align with the class description. They are concise and clear in their purpose.However, to improve robustness, consider adding a null check in the
enabled
method:@Override protected Double enabled(Double x) { + if (x == null) { + return null; // or throw an exception, depending on your error handling strategy + } return curve(x); }This change will prevent potential
NullPointerException
s if the inputx
is null.src/main/java/net/frc5183/librobot/math/curve/LinearCurve.java (1)
33-63
: LGTM: Getter and setter methods are well-implemented.The getter and setter methods for
slope
andyIntercept
are correctly implemented with clear Javadoc comments.Consider adding validation in the setter methods to ensure that only valid values are set. For example:
public void setSlope(double slope) { if (Double.isFinite(slope)) { this.slope = slope; } else { throw new IllegalArgumentException("Slope must be a finite number"); } }This would prevent setting invalid values like NaN or Infinity.
src/main/java/net/frc5183/librobot/math/curve/RadicalCurve.java (3)
3-6
: Enhance class-level Javadoc commentThe current Javadoc comment provides a good basic description of the class. However, it could be improved by adding more details about the parameters and their constraints.
Consider expanding the Javadoc comment to include:
- Descriptions of A, B, and C parameters
- Any constraints on these parameters (e.g., A != 0)
- The domain and range of the function
Example:
/** * A {@link Curve} which represents a radical equation in the form y = (x+C)^(1/A)+B. * * @param A The root degree (A != 0) * @param B The vertical shift * @param C The horizontal shift * * Domain: x >= -C when A > 0, x <= -C when A < 0 * Range: y >= B when A > 0, y <= B when A < 0 */
22-32
: Enhance constructor Javadoc and consider adding parameter validationThe constructor's Javadoc comment could be more informative about parameter constraints.
- Enhance the Javadoc comment to include parameter constraints. For example:
/** * Creates a new {@link RadicalCurve} with the given A, B, and C values. * @param a The "A" variable in the curve equation. Must not be zero. * @param b The "B" variable in the curve equation. * @param c The "C" variable in the curve equation. * @throws IllegalArgumentException if a is zero. */
- Consider adding parameter validation in the constructor:
public RadicalCurve(Double a, Double b, Double c) { if (a == 0) { throw new IllegalArgumentException("Parameter 'a' must not be zero."); } this.a = a; this.b = b; this.c = c; }
40-86
: Enhance Javadoc comments for setter methodsThe current Javadoc comments for the setter methods could be more informative about the mathematical implications of changing these values.
Consider updating the Javadoc comments for the setter methods to include more details. For example:
/** * Sets the "A" variable in the curve equation. * Changing this value affects the root degree of the radical function. * @param a The new "A" variable in the curve equation. Must not be zero. * @throws IllegalArgumentException if a is zero. */ public void setA(Double a) { if (a == 0) { throw new IllegalArgumentException("Parameter 'a' must not be zero."); } this.a = a; this.inverseA = 1 / a; // Update cached value } /** * Sets the "B" variable in the curve equation. * Changing this value shifts the entire curve vertically. * @param b The new "B" variable in the curve equation. */ public void setB(Double b) { this.b = b; } /** * Sets the "C" variable in the curve equation. * Changing this value shifts the curve horizontally and affects the domain of the function. * @param c The new "C" variable in the curve equation. */ public void setC(Double c) { this.c = c; }These enhanced comments provide more context about how changing each variable affects the curve's behavior.
src/main/java/net/frc5183/librobot/math/curve/QuadraticCurve.java (2)
1-20
: Class structure looks good, consider using primitive types.The class structure is well-designed for representing a quadratic curve. The fields are appropriately declared as private with clear comments.
Consider using primitive
double
instead ofDouble
for the coefficients if null values are not needed. This would prevent potential NullPointerExceptions and improve performance. If you decide to keepDouble
, ensure proper null checks are in place where these fields are used.
48-54
: Setter methods are correct, consider adding input validation.The setter methods for a, b, and c are implemented correctly and have clear, descriptive comments.
Consider adding input validation to prevent setting null values or other invalid states. For example:
public void setA(Double a) { if (a == null) { throw new IllegalArgumentException("Coefficient 'a' cannot be null"); } this.a = a; }Apply similar checks to setB and setC methods. This will help maintain the integrity of the QuadraticCurve object.
Also applies to: 64-70, 80-86
src/main/java/net/frc5183/librobot/math/curve/DoubleTimedCurve.java (2)
3-6
: Enhance the class-level Javadoc commentThe current Javadoc provides a basic description of the class. Consider expanding it to include more details about the purpose and behavior of the
DoubleTimedCurve
class.Here's a suggested improvement:
/** * A {@link TimedCurve} that toggles between two curves based on its enabled/disabled state. * This class allows for dynamic switching between two different curve behaviors, * defined by the enabledCurve and disabledCurve. */ public class DoubleTimedCurve extends TimedCurve {
41-63
: Enhance Javadoc for getter methodsWhile the getter methods are correctly implemented, their Javadoc comments could be more informative. Consider adding more context about when these methods might be used.
Here's a suggested improvement for
getEnabledCurve
:/** * Returns the curve used when this DoubleTimedCurve is in an enabled state. * This curve determines the behavior of the `enabled` method. * * @return The Curve object used when this DoubleTimedCurve is enabled. */ public Curve getEnabledCurve() { return enabledCurve; }Apply a similar improvement to
getDisabledCurve
.src/main/java/net/frc5183/librobot/math/curve/TimedCurve.java (2)
34-37
: Consider starting the Timer in the constructorThe constructor initializes the delay fields correctly. However, it doesn't start the Timer. Consider adding
timer.start();
at the end of the constructor to ensure the Timer begins running immediately upon object creation.public TimedCurve(Double delayEnabled, Double delayDisabled) { this.delayEnabled = delayEnabled; this.delayDisabled = delayDisabled; + timer.start(); }
39-50
: Add a comment explaining the logic and consider using if-else for clarityThe
curve
method implements the core logic for toggling between enabled and disabled states correctly. However, consider adding a comment explaining the logic and using an if-else statement instead of a ternary operator for better readability.@Override public Double curve(Double x) { + // Check if it's time to toggle the state based on the current state and elapsed time if (disabled && timer.hasElapsed(delayDisabled)) { disabled = false; timer.reset(); } else if (!disabled && timer.hasElapsed(delayEnabled)) { disabled = true; timer.reset(); } - return disabled ? disabled(x) : enabled(x); + // Return the appropriate value based on the current state + if (disabled) { + return disabled(x); + } else { + return enabled(x); + } }src/main/java/net/frc5183/librobot/math/curve/PiecewiseCurve.java (5)
19-50
: LGTM: Constructors are well-implemented, with a minor suggestion.The constructors provide good flexibility for creating
PiecewiseCurve
instances. The use ofMap.of()
andMap.ofEntries()
is appropriate for creating immutable maps.Consider adding a
@SafeVarargs
annotation to the constructor that takes aMap<Function<Double, Boolean>, Curve>
parameter. While not strictly necessary, it would be consistent with the other varargs constructor and suppress any potential warnings.+ @SafeVarargs public PiecewiseCurve(Map<Function<Double, Boolean>, Curve> curves) { this.curves = curves; }
52-60
: LGTM: curve method implementation is correct, with a potential optimization.The
curve
method correctly implements the piecewise function logic, iterating through the conditions and returning the value of the first matching curve. The default return value of 0d is consistent with the class documentation.Consider using the Stream API for a more concise implementation and potential performance improvement:
@Override public Double curve(Double x) { - for (Map.Entry<Function<Double, Boolean>, Curve> entry : curves.entrySet()) { - if (entry.getKey().apply(x)) { - return entry.getValue().curve(x); - } - } - return 0d; + return curves.entrySet().stream() + .filter(entry -> entry.getKey().apply(x)) + .findFirst() + .map(entry -> entry.getValue().curve(x)) + .orElse(0d); }This implementation may be more efficient for large maps, as it can short-circuit the evaluation once a matching condition is found.
86-93
: LGTM: replace method is correctly implemented, with a minor suggestion.The
replace
method provides a clean way to update a curve for a given condition without exposing the internal map structure.For consistency with other methods in the class, consider returning the previous curve (if any) associated with the condition:
- public void replace(Function<Double, Boolean> condition, Curve curve) { - curves.replace(condition, curve); + public Curve replace(Function<Double, Boolean> condition, Curve curve) { + return curves.replace(condition, curve); }This change would make the method more informative and align it with the behavior of
java.util.Map.replace()
.
95-102
: LGTM: put method is correctly implemented, with a minor suggestion.The
put
method provides a clean way to add a new condition-curve pair to the piecewise curve without exposing the internal map structure.For consistency with the
java.util.Map.put()
method and to provide more information to the caller, consider returning the previous curve (if any) associated with the condition:- public void put(Function<Double, Boolean> condition, Curve curve) { - curves.put(condition, curve); + public Curve put(Function<Double, Boolean> condition, Curve curve) { + return curves.put(condition, curve); }This change would make the method more informative and align it with the behavior of
java.util.Map.put()
.
1-127
: Overall, the PiecewiseCurve class is well-designed and implemented.The class provides a robust and efficient implementation of a piecewise curve using a map of conditions to curves. The methods offer a good balance of functionality and encapsulation, allowing for easy creation, access, and manipulation of the curve without exposing the internal map structure.
Consider adding a method to combine two
PiecewiseCurve
instances, which could be useful in more complex scenarios:public PiecewiseCurve combine(PiecewiseCurve other) { Map<Function<Double, Boolean>, Curve> combinedCurves = new HashMap<>(this.curves); other.forEachEntry((condition, curve) -> combinedCurves.putIfAbsent(condition, curve)); return new PiecewiseCurve(combinedCurves); }This method would allow users to create more complex piecewise curves by combining existing ones, enhancing the flexibility and composability of the class.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (12)
- build.gradle (1 hunks)
- src/main/java/net/frc5183/librobot/math/curve/Curve.java (1 hunks)
- src/main/java/net/frc5183/librobot/math/curve/DoubleTimedCurve.java (1 hunks)
- src/main/java/net/frc5183/librobot/math/curve/ExponentialCurve.java (1 hunks)
- src/main/java/net/frc5183/librobot/math/curve/LimitedCurve.java (1 hunks)
- src/main/java/net/frc5183/librobot/math/curve/LinearCurve.java (1 hunks)
- src/main/java/net/frc5183/librobot/math/curve/NormalTimedCurve.java (1 hunks)
- src/main/java/net/frc5183/librobot/math/curve/PiecewiseCurve.java (1 hunks)
- src/main/java/net/frc5183/librobot/math/curve/QuadraticCurve.java (1 hunks)
- src/main/java/net/frc5183/librobot/math/curve/RadicalCurve.java (1 hunks)
- src/main/java/net/frc5183/librobot/math/curve/TimedCurve.java (1 hunks)
- src/main/java/net/frc5183/librobot/math/curve/ZeroTimedCurve.java (1 hunks)
🧰 Additional context used
🪛 GitHub Check: pmd
src/main/java/net/frc5183/librobot/math/curve/ExponentialCurve.java
[warning] 23-23: This statement should have braces
Enforce a policy for braces on control statements. It is recommended to use braces on 'if ... else'
statements and loop statements, even if they are optional. This usually makes the code clearer, and
helps prepare the future when you need to add another statement. That said, this rule lets you control
which statements are required to have braces via properties.From 6.2.0 on, this rule supersedes WhileLoopMustUseBraces, ForLoopMustUseBraces, IfStmtMustUseBraces,
and IfElseStmtMustUseBraces.ControlStatementBraces (Priority: 3, Ruleset: Code Style)
https://docs.pmd-code.org/pmd-doc-7.6.0/pmd_rules_java_codestyle.html#controlstatementbraces
[warning] 26-26: Useless parentheses.
Parenthesized expressions are used to override the default operator precedence
rules. Parentheses whose removal would not change the relative nesting of operators
are unnecessary, because they don't change the semantics of the enclosing expression.Some parentheses that strictly speaking are unnecessary, may still be considered useful
for readability. This rule allows to ignore violations on two kinds of unnecessary parentheses:
- "Clarifying" parentheses, which separate operators of difference precedence. While
unnecessary, they make precedence rules explicit, which may be useful for rarely used
operators. For example:(a + b) & c // is equivalent to `a + b & c`, but probably clearerUnset the property
ignoreClarifying
to report them.
- "Balancing" parentheses, which are unnecessary but visually balance out another pair
of parentheses around an equality operator. For example, those two expressions are equivalent:(a == null) != (b == null) a == null != (b == null)The parentheses on the right are required, and the parentheses on the left are
just more visually pleasing. Unset the propertyignoreBalancing
to report them.UselessParentheses (Priority: 4, Ruleset: Code Style)
https://docs.pmd-code.org/pmd-doc-7.6.0/pmd_rules_java_codestyle.html#uselessparentheses
[warning] 26-26: Useless parentheses.
Parenthesized expressions are used to override the default operator precedence
rules. Parentheses whose removal would not change the relative nesting of operators
are unnecessary, because they don't change the semantics of the enclosing expression.Some parentheses that strictly speaking are unnecessary, may still be considered useful
for readability. This rule allows to ignore violations on two kinds of unnecessary parentheses:
- "Clarifying" parentheses, which separate operators of difference precedence. While
unnecessary, they make precedence rules explicit, which may be useful for rarely used
operators. For example:(a + b) & c // is equivalent to `a + b & c`, but probably clearerUnset the property
ignoreClarifying
to report them.
- "Balancing" parentheses, which are unnecessary but visually balance out another pair
of parentheses around an equality operator. For example, those two expressions are equivalent:(a == null) != (b == null) a == null != (b == null)The parentheses on the right are required, and the parentheses on the left are
just more visually pleasing. Unset the propertyignoreBalancing
to report them.UselessParentheses (Priority: 4, Ruleset: Code Style)
https://docs.pmd-code.org/pmd-doc-7.6.0/pmd_rules_java_codestyle.html#uselessparentheses
🔇 Additional comments (34)
src/main/java/net/frc5183/librobot/math/curve/Curve.java (3)
1-1
: LGTM: Package declaration is correct and follows conventions.The package name
net.frc5183.librobot.math.curve
is well-structured and follows Java naming conventions. It clearly indicates that this is part of a robotics library (librobot
) and specifically belongs to the math and curve-related functionality.
6-6
: LGTM: Class declaration is correct and follows best practices.The
Curve
class is properly declared as an abstract public class. This aligns with its intended purpose as a base class for various curve implementations. The class name is concise, meaningful, and follows Java naming conventions.
12-12
: Consider using primitivedouble
instead ofDouble
.The
curve
method is correctly declared as abstract and public. However, the use ofDouble
for both parameter and return type instead of the primitivedouble
is worth discussing:
- Using
Double
allows for null values, which might be intentional for representing undefined points on the curve.- However, it also introduces the possibility of null pointer exceptions if not handled carefully.
- Using primitive
double
would be more efficient and safer if null values are not needed.Consider whether allowing null values is necessary for your use case. If not, using
double
might be preferable:public abstract double curve(double x);If you decide to keep
Double
, ensure that null checks are implemented in all concrete subclasses to prevent null pointer exceptions.To verify the current usage, you can run the following command:
This will help identify existing implementations and how they handle potential null values.
src/main/java/net/frc5183/librobot/math/curve/ExponentialCurve.java (1)
1-44
: Overall assessment: Well-implemented with minor suggestions for improvement.The
ExponentialCurve
class is a solid implementation of the exponential curve as described in the PR objectives. It correctly extends theCurve
abstract class and implements the mathematical formula as specified. The code is generally well-structured and documented.Key points:
- The class-level Javadoc could be enhanced for better clarity.
- The
curve
method correctly implements the formula and handles edge cases.- Consider adding input validation to the
setExaggeration
method.- Minor improvements to code style (adding braces to if statement) have been suggested.
These minor enhancements will further improve the already well-implemented class.
🧰 Tools
🪛 GitHub Check: pmd
[warning] 23-23: This statement should have braces
Enforce a policy for braces on control statements. It is recommended to use braces on 'if ... else'
statements and loop statements, even if they are optional. This usually makes the code clearer, and
helps prepare the future when you need to add another statement. That said, this rule lets you control
which statements are required to have braces via properties.From 6.2.0 on, this rule supersedes WhileLoopMustUseBraces, ForLoopMustUseBraces, IfStmtMustUseBraces,
and IfElseStmtMustUseBraces.ControlStatementBraces (Priority: 3, Ruleset: Code Style)
https://docs.pmd-code.org/pmd-doc-7.6.0/pmd_rules_java_codestyle.html#controlstatementbraces
[warning] 26-26: Useless parentheses.
Parenthesized expressions are used to override the default operator precedence
rules. Parentheses whose removal would not change the relative nesting of operators
are unnecessary, because they don't change the semantics of the enclosing expression.Some parentheses that strictly speaking are unnecessary, may still be considered useful
for readability. This rule allows to ignore violations on two kinds of unnecessary parentheses:
- "Clarifying" parentheses, which separate operators of difference precedence. While
unnecessary, they make precedence rules explicit, which may be useful for rarely used
operators. For example:(a + b) & c // is equivalent to `a + b & c`, but probably clearerUnset the property
ignoreClarifying
to report them.
- "Balancing" parentheses, which are unnecessary but visually balance out another pair
of parentheses around an equality operator. For example, those two expressions are equivalent:(a == null) != (b == null) a == null != (b == null)The parentheses on the right are required, and the parentheses on the left are
just more visually pleasing. Unset the propertyignoreBalancing
to report them.UselessParentheses (Priority: 4, Ruleset: Code Style)
https://docs.pmd-code.org/pmd-doc-7.6.0/pmd_rules_java_codestyle.html#uselessparentheses
[warning] 26-26: Useless parentheses.
Parenthesized expressions are used to override the default operator precedence
rules. Parentheses whose removal would not change the relative nesting of operators
are unnecessary, because they don't change the semantics of the enclosing expression.Some parentheses that strictly speaking are unnecessary, may still be considered useful
for readability. This rule allows to ignore violations on two kinds of unnecessary parentheses:
- "Clarifying" parentheses, which separate operators of difference precedence. While
unnecessary, they make precedence rules explicit, which may be useful for rarely used
operators. For example:(a + b) & c // is equivalent to `a + b & c`, but probably clearerUnset the property
ignoreClarifying
to report them.
- "Balancing" parentheses, which are unnecessary but visually balance out another pair
of parentheses around an equality operator. For example, those two expressions are equivalent:(a == null) != (b == null) a == null != (b == null)The parentheses on the right are required, and the parentheses on the left are
just more visually pleasing. Unset the propertyignoreBalancing
to report them.UselessParentheses (Priority: 4, Ruleset: Code Style)
https://docs.pmd-code.org/pmd-doc-7.6.0/pmd_rules_java_codestyle.html#uselessparenthesessrc/main/java/net/frc5183/librobot/math/curve/NormalTimedCurve.java (3)
6-10
: LGTM: Class declaration and member variable are well-defined.The class extension and member variable declaration are correct. The documentation for the
curve
variable is clear and concise.
12-21
: LGTM: Constructor is well-implemented and documented.The constructor is correctly implemented, calling the superclass constructor and initializing the
curve
member variable. The documentation clearly describes all parameters.
33-47
: LGTM: Getter and setter methods are well-implemented and documented.The getter and setter methods for the
curve
variable are correctly implemented and follow Java conventions. The documentation for both methods is clear and concise.src/main/java/net/frc5183/librobot/math/curve/ZeroTimedCurve.java (7)
1-6
: LGTM: Class declaration and package statement are well-structured.The class declaration, package statement, and Javadoc comment are clear and follow Java conventions. The class name
ZeroTimedCurve
is descriptive and accurately represents its functionality.
7-10
: LGTM: Field declaration is properly encapsulated and documented.The
curve
field is correctly declared as private with an informative Javadoc comment, adhering to good Java practices.
12-21
: LGTM: Constructor is well-implemented and documented.The constructor is properly implemented, calling the superclass constructor and initializing the
curve
field. The Javadoc comment clearly explains all parameters.
23-26
: LGTM:enabled
method correctly implements the specified behavior.The
enabled
method properly overrides the superclass method and correctly returns the value of the curve when enabled.
28-31
: LGTM:disabled
method correctly implements the specified behavior.The
disabled
method properly overrides the superclass method and correctly returns 0.0 when the curve is disabled.
33-47
: LGTM: Getter and setter methods are properly implemented and documented.The
getCurve()
andsetCurve(Curve curve)
methods are correctly implemented with appropriate Javadoc comments.
1-48
: Excellent implementation of the ZeroTimedCurve class.The
ZeroTimedCurve
class is well-implemented, following Java best practices and conventions. It correctly extendsTimedCurve
and implements the behavior described in the PR objectives. The code is clean, well-documented, and properly encapsulated. Great job!src/main/java/net/frc5183/librobot/math/curve/LinearCurve.java (4)
1-6
: LGTM: Class declaration and package statement are well-structured.The class declaration, package statement, and class-level Javadoc comment are appropriately implemented. The class extends Curve as expected for a specific curve type.
7-15
: LGTM: Field declarations are well-implemented.The private fields
slope
andyIntercept
are appropriately declared with clear Javadoc comments. The use ofdouble
type is suitable for these mathematical concepts.
17-25
: LGTM: Constructor is well-implemented.The constructor correctly initializes the
slope
andyIntercept
fields with the provided values. The Javadoc comment clearly describes the purpose and parameters of the constructor.
1-64
: Overall, LinearCurve is well-implemented with room for minor enhancements.The
LinearCurve
class provides a solid implementation of a linear curve. It correctly extends theCurve
class, provides appropriate fields with getters and setters, and implements thecurve
method as expected. The code is well-documented with clear Javadoc comments.Consider the suggested improvements regarding primitive types, null checks, and input validation to further enhance the robustness of the class. These changes would make the class more resilient to edge cases and potential misuse.
Great job on implementing this mathematical concept in a clear and concise manner!
build.gradle (1)
47-47
: LGTM: WPIMath dependency added correctlyThe addition of the WPIMath library dependency is correct and consistent with other WPILib dependencies. This change aligns well with the PR objectives, which mention integrating the WPILib math library into the project.
src/main/java/net/frc5183/librobot/math/curve/LimitedCurve.java (2)
1-6
: LGTM: Class declaration and documentation are well-defined.The class declaration and its accompanying Javadoc comment are clear and concise, effectively communicating the purpose of the
LimitedCurve
class.
1-87
: Overall assessment: Well-structured class with room for robustness improvements.The
LimitedCurve
class is well-designed and implements the intended functionality effectively. However, there are several opportunities to enhance its robustness and type safety:
- Consider using primitive
double
instead ofDouble
formin
andmax
to prevent null values and potential null pointer exceptions.- Add parameter validation in the constructor to ensure valid input.
- Implement null checks in the
curve
method to handle cases where limits are not set.- Add input validation in setter methods to maintain consistent state.
Addressing these points will significantly improve the reliability and usability of the
LimitedCurve
class.src/main/java/net/frc5183/librobot/math/curve/RadicalCurve.java (1)
1-87
: Overall assessment of RadicalCurve classThe
RadicalCurve
class is a well-structured implementation of a radical curve. It correctly extends theCurve
class and provides the necessary functionality to represent and manipulate a radical equation.Positive aspects:
- Clear class structure with appropriate member variables.
- Correct implementation of the radical equation in the
curve
method.- Provision of getter and setter methods for all parameters.
Areas for improvement:
- Enhanced exception handling in the
curve
method and constructor.- More detailed Javadoc comments, especially for the class and setter methods.
- Consideration of using primitive types instead of wrapper classes for member variables.
- Potential performance optimization by caching the inverse of 'a'.
Implementing these suggestions will result in a more robust, efficient, and well-documented class.
src/main/java/net/frc5183/librobot/math/curve/QuadraticCurve.java (3)
22-32
: Constructor implementation is correct and well-documented.The constructor correctly initializes the fields with the provided values. The comment clearly explains the purpose and parameters of the constructor.
40-46
: Getter methods are correctly implemented and well-documented.The getter methods for a, b, and c are implemented correctly. Each method has a clear and descriptive comment explaining its purpose.
Also applies to: 56-62, 72-78
1-87
: Overall, the QuadraticCurve implementation is well-structured and documented.The class provides a solid representation of a quadratic curve with appropriate fields, constructor, and methods. The code is generally well-written and commented. The suggested improvements (performance optimization in the curve method, null checks, and input validation in setters) will enhance the robustness and efficiency of the implementation without changing its core functionality.
src/main/java/net/frc5183/librobot/math/curve/DoubleTimedCurve.java (4)
7-15
: Field declarations look goodThe private fields
enabledCurve
anddisabledCurve
are well-declared with appropriate Javadoc comments. They follow good encapsulation practices and naming conventions.
17-29
: Constructor implementation is correct and well-documentedThe constructor is properly implemented, initializing all necessary fields and calling the superclass constructor. The Javadoc comment is comprehensive, including descriptions for all parameters and a reference to the superclass constructor.
31-39
: Overridden methods are correctly implementedThe
enabled
anddisabled
methods are properly overridden and implement the expected behavior of delegating to their respective curves. The use of the @OverRide annotation is correct.
1-72
: Overall, well-implemented class with minor improvement opportunitiesThe
DoubleTimedCurve
class is well-structured and correctly implements the intended functionality. It adheres to Java conventions and OOP principles. The suggested improvements, including enhanced Javadoc comments, input validation for setters, and the addition of atoString()
method, will further increase the robustness and maintainability of the class.src/main/java/net/frc5183/librobot/math/curve/TimedCurve.java (2)
1-27
: LGTM: Well-structured class declaration and fieldsThe abstract class declaration and field definitions are well-structured. The use of
Double
for delay values allows for fractional seconds, providing good precision for timing control.
52-64
: LGTM: Well-defined abstract methodsThe abstract methods
enabled(Double x)
anddisabled(Double x)
are well-defined with clear and informative JavaDoc comments. This design allows for flexible implementations in subclasses.src/main/java/net/frc5183/librobot/math/curve/PiecewiseCurve.java (3)
1-17
: LGTM: Class declaration and field look good.The
PiecewiseCurve
class is correctly declared as extendingCurve
, and thecurves
field is appropriately defined as a private final Map. This design choice allows for efficient storage and retrieval of condition-curve pairs.
62-84
: LGTM: forEach methods are well-implemented.The
forEach
,forEachKey
, andforEachEntry
methods provide a convenient and type-safe way to iterate over the curves, conditions, and both respectively. The use ofConsumer
andBiConsumer
is appropriate, and the implementation correctly delegates to the underlying map's methods.
104-126
: LGTM: get, remove, and clear methods are correctly implemented.The
get
,remove
, andclear
methods provide essential operations for manipulating the piecewise curve without exposing the internal map structure. The implementations are straightforward and correctly delegate to the corresponding methods of the underlying map.
src/main/java/net/frc5183/librobot/math/curve/ExponentialCurve.java
Outdated
Show resolved
Hide resolved
src/main/java/net/frc5183/librobot/math/curve/LimitedCurve.java
Outdated
Show resolved
Hide resolved
src/main/java/net/frc5183/librobot/math/curve/LimitedCurve.java
Outdated
Show resolved
Hide resolved
src/main/java/net/frc5183/librobot/math/curve/LimitedCurve.java
Outdated
Show resolved
Hide resolved
src/main/java/net/frc5183/librobot/math/curve/RadicalCurve.java
Outdated
Show resolved
Hide resolved
src/main/java/net/frc5183/librobot/math/curve/QuadraticCurve.java
Outdated
Show resolved
Hide resolved
src/main/java/net/frc5183/librobot/math/curve/DoubleTimedCurve.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Outside diff range and nitpick comments (1)
src/main/java/net/frc5183/librobot/math/curve/ExponentialCurve.java (1)
21-27
: Consider adding Javadoc to the curve methodThe
curve
method is well-implemented and correctly handles the case where x is 0. However, it would benefit from additional documentation to explain its behavior and parameters.Consider adding a Javadoc comment to the
curve
method:/** * Calculates the y-value of the exponential curve for a given x-value. * @param x The input value. * @return The calculated y-value of the curve. * @implNote Returns 0 when x is 0 to avoid division by zero. */ @Override public Double curve(Double x) { // ... existing implementation ... }This additional documentation will improve the readability and maintainability of the code.
🧰 Tools
🪛 GitHub Check: pmd
[warning] 23-23: This statement should have braces
Enforce a policy for braces on control statements. It is recommended to use braces on 'if ... else'
statements and loop statements, even if they are optional. This usually makes the code clearer, and
helps prepare the future when you need to add another statement. That said, this rule lets you control
which statements are required to have braces via properties.From 6.2.0 on, this rule supersedes WhileLoopMustUseBraces, ForLoopMustUseBraces, IfStmtMustUseBraces,
and IfElseStmtMustUseBraces.ControlStatementBraces (Priority: 3, Ruleset: Code Style)
https://docs.pmd-code.org/pmd-doc-7.6.0/pmd_rules_java_codestyle.html#controlstatementbraces
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
- src/main/java/net/frc5183/librobot/math/curve/ExponentialCurve.java (1 hunks)
🧰 Additional context used
🪛 GitHub Check: pmd
src/main/java/net/frc5183/librobot/math/curve/ExponentialCurve.java
[warning] 23-23: This statement should have braces
Enforce a policy for braces on control statements. It is recommended to use braces on 'if ... else'
statements and loop statements, even if they are optional. This usually makes the code clearer, and
helps prepare the future when you need to add another statement. That said, this rule lets you control
which statements are required to have braces via properties.From 6.2.0 on, this rule supersedes WhileLoopMustUseBraces, ForLoopMustUseBraces, IfStmtMustUseBraces,
and IfElseStmtMustUseBraces.ControlStatementBraces (Priority: 3, Ruleset: Code Style)
https://docs.pmd-code.org/pmd-doc-7.6.0/pmd_rules_java_codestyle.html#controlstatementbraces
🔇 Additional comments (3)
src/main/java/net/frc5183/librobot/math/curve/ExponentialCurve.java (3)
1-11
: LGTM: Well-structured class with clear documentationThe class declaration, documentation, and field definition are well-implemented. The Javadoc comment clearly explains the purpose of the class and the mathematical formula it represents, which is helpful for understanding and maintenance.
29-43
: Implement input validation in setExaggeration methodThe getter method is well-implemented and documented. However, as noted in a previous review comment, the
setExaggeration
method should include input validation to ensure the exaggeration value remains positive.I agree with the previous review comment. Please implement the suggested input validation in the
setExaggeration
method to maintain the integrity of the exponential curve calculation.
23-23
: Consider the trade-off between conciseness and consistency for braces usageA static analysis tool has suggested adding braces to the if statement on this line. While using braces consistently can improve readability and reduce the risk of errors when modifying code in the future, the current implementation is clear and concise for a single-line return statement.
Consider the coding style guidelines for your project. If there's no strict rule requiring braces for all control statements, the current implementation can be maintained for its simplicity. However, if consistency is a priority, you may want to add braces:
if (x == 0) { return 0d; }Please verify the preferred style for your project and update if necessary.
🧰 Tools
🪛 GitHub Check: pmd
[warning] 23-23: This statement should have braces
Enforce a policy for braces on control statements. It is recommended to use braces on 'if ... else'
statements and loop statements, even if they are optional. This usually makes the code clearer, and
helps prepare the future when you need to add another statement. That said, this rule lets you control
which statements are required to have braces via properties.From 6.2.0 on, this rule supersedes WhileLoopMustUseBraces, ForLoopMustUseBraces, IfStmtMustUseBraces,
and IfElseStmtMustUseBraces.ControlStatementBraces (Priority: 3, Ruleset: Code Style)
https://docs.pmd-code.org/pmd-doc-7.6.0/pmd_rules_java_codestyle.html#controlstatementbraces
src/main/java/net/frc5183/librobot/math/curve/ExponentialCurve.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me. Look over Radical curve as discussed in the other comment and then you're good to go.
This pull requests implements an abstract Curve utility class and implements the following subclasses:
Also adds the WPILib math library to the project.
Summary by CodeRabbit
New Features
Curve
,DoubleTimedCurve
,ExponentialCurve
,LimitedCurve
,LinearCurve
,NormalTimedCurve
,PiecewiseCurve
,QuadraticCurve
,RadicalCurve
,TimedCurve
, andZeroTimedCurve
to support various mathematical functions and behaviors.Improvements